import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;


public class HRASystem {
	private final static String STARTUP_FILE = "startup.txt";
	private final static String PAYROLL_FILE = "payroll.txt";
	private final static String DEPARTMENTS_FILE = "departments.txt";
	private final static String EMPLOYEES_FILE = "employees.txt";
	protected FileManager startup, payroll, departments_file, employees_file;
	private Map<Integer, Employee> employees;
	private ArrayList<Department> departments;
	private int employeeId=0;
	
	public HRASystem() throws SystemException, FileNotFoundException, IOException, Exception{
		employees = new HashMap<Integer, Employee>();
		departments = new ArrayList<Department>();	
		startup = new TextFileManager(STARTUP_FILE);
		payroll = new TextFileManager(PAYROLL_FILE);
		departments_file = new BinaryFileManager(DEPARTMENTS_FILE);
		employees_file   = new BinaryFileManager(EMPLOYEES_FILE);
		
		//Load data from departments.txt and employees.txt if they exist else initialise data from startup.txt text file
		if(departments_file.getFile().exists() && employees_file.getFile().exists()){
			//Loading from binary files
			loadDepartments();
			loadEmployees();
		}
		else{
			//Loading from text file
			cleanStartup();
		}
	}
	
	public void cleanStartup() throws Exception{
		//Load department ArrayList with data from startup.txt
		departments = (ArrayList<Department>) startup.loadData();
		if(departments == null){
			//Throws an exception if departments ArrayList is null (startup.txt file missing)
			throw new FileNotFoundException();
		}
		else{
			//Traverse through each department and add employees to employees Map
			for(Department d : departments){
				//Get all employees from the certain department
				ArrayList<Employee> tmpEmployees = d.getEmployees();
				for(Employee e : tmpEmployees){
					//Map with Key = employee ID, Value = employee
					employees.put(e.getId(), e);
					//Increase employeeId in order to add new employee with incremental ID
					employeeId = e.getId();
				}
			}
			System.out.println("Last ID: "+employeeId);
		}
	}
	
	public int getEmployeeId(){
		return employeeId;
	}
	
	public void setEmployeeId(int id){
		employeeId = id;
	}
	
	public void setMaxId(int id){
		//Max id check and assign max value
		if(id > employeeId){
			employeeId = id+1;
		}
	}
	
	public void loadDepartments() throws Exception{
		departments = (ArrayList<Department>) departments_file.loadData();
	}
	
	public void loadEmployees() throws Exception{
		ArrayList<Employee> em = (ArrayList<Employee>) employees_file.loadData();
		for(Employee e : em){
			employees.put(e.getId(), e);
			setMaxId(e.getId());
		}
		System.out.println("Last ID:" + employeeId);
	}
	
	public void addDepartment(Department d){
		departments.add(d);
	}
	
	public void deleteDepartment(Department d) throws SystemException{
		//Only remove department is there are no employees
		if(d.getEmployees().isEmpty()){
			departments.remove(d);
		}
		else{
			//Throw an exception when department is not yet empty and gets deleted
			throw new SystemException(SystemErrors.DEPARTMENT_NOT_EMPTY);
		}
	}
	
	public Department getDepartment(int idx){
		return departments.get(idx);
	}
	
	public ArrayList<Department> getAllDepartments(){
		return departments;
	}
	
	public void addEmployee(Employee e) throws SystemException{
		employees.put(e.getId(), e);
	}
	
	public boolean deleteEmployee(Employee e){
		boolean result = false;
		if(employees.containsValue(e)){
			//Remove employee from Map based on Id
			employees.remove(e.getId());
			//Remove same employee from his/her department
			for(Department d : departments){
				for(Employee em : d.getEmployees()){
					if(e.equals(em)){
						d.deleteEmployee(em);
					}
				}
			}
		}
		return result;
	}
	public Map<Integer,Employee> getAllEmployees(){
		return employees;
	}
	
	public ArrayList<Employee> getEmployeesList(){
		//Traverse through Map and add all employee to ArrayList and return it 
		ArrayList<Employee> e = new ArrayList<Employee>();
		for(Integer i : employees.keySet()){
			e.add(employees.get(i));
		}
		return e;
	}
	
	public ArrayList<Employee> getEmployeesWithNoDepartment(){
		//Traverse through Map and add all employee with no department to ArrayList and return it 
		ArrayList<Employee> e = new ArrayList<Employee>();
		for(Integer i : employees.keySet()){
			if(employees.get(i).getDepartment() == null){
				e.add(employees.get(i));
			}
		}
		return e;
	}
	
	public void assignEmployeeToDepartment(Department d, Employee e) throws SystemException{
		d.addEmployee(e);
	}
	
	public void assignHeadToDepartment(Department d, Employee e) throws SystemException{
		d.setHead(e);
	}
	
	public void unassignHeadFromDepartment(Department d){
		d.getHead().leaveDepartment();
		d.removeHead();
	}
	
	public ArrayList<Employee> getEmployeesFromDepartment(Department d){
		return d.getEmployees();
	}
	
}
